package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepository;
import com.atguigu.tingshu.search.repository.SuggestIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private AlbumIndexRepository albumIndexRepository;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private SuggestIndexRepository suggestIndexRepository;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String dimension) {
        //  hget key field;
        return (List<AlbumInfoIndex>) this.redisTemplate.opsForHash().get(RedisConstant.RANKING_KEY_PREFIX+category1Id,dimension);
    }

    @Override
    public void updateLatelyAlbumRanking() {
        //  先查询所有的一级分类数据.
        Result<List<BaseCategory1>> baseCategory1Result = categoryFeignClient.findAllCategory1();
        Assert.notNull(baseCategory1Result,"一级分类数据结果集为空");
        List<BaseCategory1> baseCategory1List = baseCategory1Result.getData();
        Assert.notNull(baseCategory1List,"一级分类数据为空");
        //  定义一个数组来存储五个维度信息.
        String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
        //  从es中查询数据，将数据放入redis中. hset key field value;
        //  循环遍历集合
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            //  查询es---
            for (String ranking : rankingDimensionArray) {
                //  通过每个分类的维度查询数据.
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                                    .query(q -> q.term(t -> t.field("category1Id").value(baseCategory1.getId())))
                                    .sort(f -> f.field(f1 -> f1.field(ranking).order(SortOrder.Desc)))
                                    .size(10)
                            ,
                            AlbumInfoIndex.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                //  获取到查询专辑集合数据。
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
                //  存储到缓存 key = ranking:category1Id
                this.redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX+baseCategory1.getId().toString(),ranking,albumInfoIndexList);
            }
        }
    }

    @Override
    public List<String> completeSuggest(String keyword) {
        //  1.  编写dsl语句.
        //  2.  执行dsl语句.
        SearchResponse<SuggestIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(
                    s -> s.index("suggestinfo").suggest(
                            sg -> sg.suggesters("keywordSuggest",
                                            f -> f.completion(c -> c.field("keyword")
                                                    .fuzzy(z -> z.fuzziness("auto")).skipDuplicates(true).size(10)).prefix(keyword))
                                    .suggesters("keywordPinyinSuggest", f -> f.completion(c -> c.field("keywordPinyin")
                                            .fuzzy(z -> z.fuzziness("auto")).skipDuplicates(true).size(10)).prefix(keyword))
                                    .suggesters("keywordSequenceSuggest", f -> f.completion(c -> c.field("keywordSequence")
                                            .fuzzy(z -> z.fuzziness("auto")).skipDuplicates(true).size(10)).prefix(keyword))
                    )
                    ,
                    SuggestIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  3.  获取结果集.
        //  创建集合
        List<String> list = new ArrayList<>();
        // 向set 集合添加数据.
        list.addAll(this.parseResultData(searchResponse, "keywordSuggest"));
        list.addAll(this.parseResultData(searchResponse, "keywordPinyinSuggest"));
        list.addAll(this.parseResultData(searchResponse, "keywordSequenceSuggest"));
        /*
        GET /suggestinfo/_search
        {
          "query": {
            "match": {
              "title": "小说"
            }
          }
        }
         */
        if (list.size() < 10) {
            SearchResponse<SuggestIndex> response = null;
            try {
                response = elasticsearchClient.search(
                        s -> s.index("suggestinfo").query(q->q.match(m->m.field("title").query(keyword)))
                        ,
                        SuggestIndex.class);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            //  获取
            for (Hit<SuggestIndex> hit : response.hits().hits()) {
                //  获取数据
                SuggestIndex suggestIndex = hit.source();
                //  添加数据
                list.add(suggestIndex.getTitle());
                //  判断是否符合长度。
                if (list.size()==10){
                    break;
                }
            }
        }
        //  返回数据
        return list;
    }

    private Collection<String> parseResultData(SearchResponse<SuggestIndex> searchResponse, String keyword) {
        //  声明一个集合
        List<String> arrayList = new ArrayList<>();
        //  根据key获取结果集数据.
        List<Suggestion<SuggestIndex>> suggestionList = searchResponse.suggest().get(keyword);
        //  判断
        if (!CollectionUtils.isEmpty(suggestionList)) {
            //  循环遍历
            for (Suggestion<SuggestIndex> suggestIndexSuggestion : suggestionList) {
                //  获取数据
                arrayList = suggestIndexSuggestion.completion().options().stream().map(suggestIndexCompletionSuggestOption -> {
                    //  获取数据
                    return suggestIndexCompletionSuggestOption.source().getTitle();
                }).collect(Collectors.toList());
            }
            //  返回数据
            return arrayList;
        }
        //  默认返回
        return arrayList;
    }

    @Override
    public List<Map> channel(Long category1Id) {
        //  创建List<Map> 集合
        //  实现类.
        Result<List<BaseCategory3>> result = categoryFeignClient.findTopBaseCategory3(category1Id);
        Assert.notNull(result, "返回三级分类数据结果集为空");
        List<BaseCategory3> baseCategory3List = result.getData();
        //  将这个集合转换为map 集合 key=category3Id value=BaseCategory3;
        //  创建map 集合
        //        HashMap<Long,Object> category3IdToMap = new HashMap<>();
        //        baseCategory3List.stream().forEach(baseCategory3 -> {
        //            //  存储map中.
        //            category3IdToMap.put(baseCategory3.getId(),baseCategory3);
        //        });
        Map<Long, BaseCategory3> category3IdToMap = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));
        //        Map<Long, BaseCategory3> category3IdToMap = baseCategory3List.stream().collect(Collectors.toMap(
        //                baseCategory3 -> baseCategory3.getId(), baseCategory3 -> baseCategory3)
        //        );
        //  获取到所有的三级分类Id
        List<Long> baseCategory3IdList = baseCategory3List.stream().map(BaseCategory3::getId).collect(Collectors.toList());
        //  获取到List<FieldValue> 集合.
        List<FieldValue> valueList = baseCategory3IdList.stream().map(baseCategory3Id -> FieldValue.of(baseCategory3Id)).collect(Collectors.toList());
        //  生成dsl语句.
        //  调用查询方法
        SearchResponse<AlbumInfoIndex> response = null;
        try {
            response = elasticsearchClient.search(s -> s.index("albuminfo")
                            .query(q -> q.terms(t -> t.field("category3Id").terms(f -> f.value(valueList))))
                            .aggregations("category3IdAgg", a -> a.terms(t -> t.field("category3Id").size(10))
                                    .aggregations("topAgg", f -> f.topHits(
                                            t -> t.size(6).sort(so -> so.field(f1 -> f1.field("buyStatNum").order(SortOrder.Desc)))
                                    ))
                            ),
                    AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  获取结果集.
        Aggregate category3IdAgg = response.aggregations().get("category3IdAgg");
        //  获取桶中的数据，{三级分类Id,对应的专辑列表}
        //  LongTermsAggregate terms = (LongTermsAggregate)category3IdAgg; terms.buckets
        List<Map> mapList = category3IdAgg.lterms().buckets().array().stream().map(longTermsBucket -> {
            //  创建map 对象
            HashMap<String, Object> map = new HashMap<>();
            //  获取三级分类Id
            long category3Id = longTermsBucket.key();
            //  获取topAgg
            List<AlbumInfoIndex> albumInfoIndexList = longTermsBucket.aggregations().get("topAgg").topHits().hits().hits().stream().map(hit -> {
                //  获取数据
                String str = hit.source().toString();
                //  数据转换
                AlbumInfoIndex albumInfoIndex = JSON.parseObject(str, AlbumInfoIndex.class);
                //  返回数据
                return albumInfoIndex;
            }).collect(Collectors.toList());
            //  其中的一个map 集合。
            map.put("baseCategory3", category3IdToMap.get(category3Id));
            map.put("list", albumInfoIndexList);
            //  返回数据
            return map;
        }).collect(Collectors.toList());
        //  返回数据。
        return mapList;
    }

    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //  1. 准备dsl语句，封装到SearchRequest对象中  2.调用客户端对象search(SearchRequest,Object.class); 3.获取查询数据
        //  调用方法获取到 SearchRequest
        SearchRequest searchRequest = this.queryDsl(albumIndexQuery);
        //  调用search() 方法
        SearchResponse<AlbumInfoIndex> response = null;
        try {
            response = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //  获取数据 list total 赋值完成了.
        AlbumSearchResponseVo albumSearchResponseVo = this.parseResultData(response);
        /*
            private Integer pageSize;//每页显示的内容
            private Integer pageNo;//当前页面
            private Long totalPages;
         */
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        //  计算总页数. 10 3 4  |  9 3 3
//        Long totalPages = albumSearchResponseVo.getTotal() % albumIndexQuery.getPageSize() != 0 ? albumSearchResponseVo.getTotal() / albumIndexQuery.getPageSize() + 1 : albumSearchResponseVo.getTotal() / albumIndexQuery.getPageSize();
        Long totalPages = (albumSearchResponseVo.getTotal() + albumIndexQuery.getPageSize() - 1) / albumIndexQuery.getPageSize();
        albumSearchResponseVo.setTotalPages(totalPages);
        //  返回数据
        return albumSearchResponseVo;
    }

    /**
     * 数据转换
     *
     * @param response
     * @return
     */
    private AlbumSearchResponseVo parseResultData(SearchResponse<AlbumInfoIndex> response) {
        //  声明一个对象
        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();
        /*
            private List<AlbumInfoIndexVo> list = new ArrayList<>();
            private Long total;//总记录数
            private Integer pageSize;//每页显示的内容
            private Integer pageNo;//当前页面
            private Long totalPages;
         */
        //  声明一个集合 albumInfoIndexVo
        List<AlbumInfoIndexVo> albumInfoIndexVoList = response.hits().hits().stream().map(albumInfoIndexHit -> {
            //  创建对象
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            //  获取数据
            AlbumInfoIndex albumInfoIndex = albumInfoIndexHit.source();
            //  赋值：
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
            //  通过关键词检索：获取高亮字段. map key-value;组成.
            if (null != albumInfoIndexHit.highlight().get("albumTitle")) {
                //  获取数据
                String albumTitle = albumInfoIndexHit.highlight().get("albumTitle").get(0);
                //  赋值数据
                albumInfoIndexVo.setAlbumTitle(albumTitle);
            }
            //  返回
            return albumInfoIndexVo;
        }).collect(Collectors.toList());
        //  赋值数据：
        albumSearchResponseVo.setList(albumInfoIndexVoList);
        //  赋值总记录数据
        albumSearchResponseVo.setTotal(response.hits().total().value());
        //  返回数据
        return albumSearchResponseVo;
    }

    /**
     * 获取到查询对象
     *
     * @param albumIndexQuery
     * @return
     */
    private SearchRequest queryDsl(AlbumIndexQuery albumIndexQuery) {
        //  创建对象
        SearchRequest.Builder searchBuilder = new SearchRequest.Builder();
        //  设置index
        searchBuilder.index("albuminfo");
        //  需要设置一个 bool 对象
        BoolQuery.Builder boolBuilder = new BoolQuery.Builder();
        //  判断关键词是否为空.
        if (!StringUtils.isEmpty(albumIndexQuery.getKeyword())) {
            //  bool-->should-->match
            boolBuilder.should(s -> s.match(m -> m.field("albumTitle").query(albumIndexQuery.getKeyword())));
            boolBuilder.should(s -> s.match(m -> m.field("albumIntro").query(albumIndexQuery.getKeyword())));
            //  boolBuilder.should(s->s.match(m->m.field("announcerName").query(albumIndexQuery.getKeyword())));
            //  index-->query-->bool-->should-->match
            //            searchBuilder.index("albuminfo").query(q -> q.bool(b -> b.should(s -> s.match(m -> m.field("albumTitle").query(albumIndexQuery.getKeyword())))
            //                            .should(s1->s1.match(m1->m1.field("albumIntro").query(albumIndexQuery.getKeyword())))
            //                    )
            //            );

            // 设置高亮 highlight-->fields-->pre_tags/post_tags
            searchBuilder.highlight(h -> h.fields("albumTitle", f -> f.preTags("<span style=color:#f86442>").postTags("</span>")));
        }

        //  判断是否有分类Id
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory1Id())) {
            //  一级分类Id
            boolBuilder.filter(f -> f.term(t -> t.field("category1Id").value(albumIndexQuery.getCategory1Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory2Id())) {
            //  一级分类Id
            boolBuilder.filter(f -> f.term(t -> t.field("category2Id").value(albumIndexQuery.getCategory2Id())));
        }
        if (!StringUtils.isEmpty(albumIndexQuery.getCategory3Id())) {
            //  一级分类Id
            boolBuilder.filter(f -> f.term(t -> t.field("category3Id").value(albumIndexQuery.getCategory3Id())));
        }

        //  根据属性Id-属性值Id进行过滤. "18:38","28:48"
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (!CollectionUtils.isEmpty(attributeList)) {
            //  循环遍历.
            for (String attribute : attributeList) {
                //  要使用:分割
                String[] split = attribute.split(":");
                //  判断
                if (null != split && split.length == 2) {
                    //  第一个应该是属性Id,第二个数据属性值Id;
                    boolBuilder.filter(f -> f.nested(
                            n -> n.path("attributeValueIndexList")
                                    .query(q -> q.bool(b -> b.must(
                                                            m -> m.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0]))
                                                    )
                                                    .must(m -> m.term(t -> t.field("attributeValueIndexList.valueId").value(split[1])))
                                    ))
                    ));
                }
            }
        }
        //  分页，排序：
        int from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        searchBuilder.from(from);
        searchBuilder.size(albumIndexQuery.getPageSize());

        //  排序：
        String order = albumIndexQuery.getOrder();
        if (!StringUtils.isEmpty(order)) {
            //  1:desc 2:desc 3:desc
            String[] split = order.split(":");
            //  判断
            if (null != split && split.length == 2) {
                //  声明字段来存储信息.
                String field = "";
                //  判断
                switch (split[0]) {
                    case "1":
                        field = "hotScore";
                        break;
                    case "2":
                        field = "playStatNum";
                        break;
                    case "3":
                        field = "createTime";
                        break;
                }
                //  排序
                String finalField = field;
                searchBuilder.sort(s -> s.field(f -> f.field(finalField).order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
            }
        }

        //  设置查询
        searchBuilder.query(boolBuilder.build()._toQuery());
        //  声明一个对象
        SearchRequest searchRequest = searchBuilder.build();
        //  打印动态生成的dsl语句.
        System.out.println("dsl:\t" + searchRequest.toString());
        //  返回对象
        return searchRequest;
    }

    @Override
    public void lowerAlbum(Long albumId) {
        //  下架
        albumIndexRepository.deleteById(albumId);
    }

    //  实现专辑上架：
    @Override
    public void upperAlbum(Long albumId) {
        //  创建对象
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            //  判断当前返回数据是否为空
            Assert.notNull(albumInfoResult, "返回专辑结果集为空");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑对象为空");
            //  赋值：
            //  属性拷贝.
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);
            //  返回数据
            return albumInfo;
        }, threadPoolExecutor);

        CompletableFuture<Void> userInfoCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            //  获取主播信息
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(albumInfo.getUserId());
            Assert.notNull(userInfoVoResult, "返回用户结果集为空");
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            Assert.notNull(userInfoVo, "用户对象为空");
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
        }, threadPoolExecutor);


        //  获取三级分类数据
        CompletableFuture<Void> categoryCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            Result<BaseCategoryView> categoryViewResult = categoryFeignClient.getCategoryView(albumInfo.getCategory3Id());
            Assert.notNull(categoryViewResult, "返回分类结果集为空");
            BaseCategoryView baseCategoryView = categoryViewResult.getData();
            Assert.notNull(baseCategoryView, "分类对象为空");
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
            albumInfoIndex.setCategory3Id(baseCategoryView.getCategory3Id());
        }, threadPoolExecutor);


        //  热度--统计信息.select * from album_stat where album_id = ?;
        int numberValue = new Random().nextInt(1000000);
        albumInfoIndex.setPlayStatNum(numberValue);
        albumInfoIndex.setBuyStatNum(numberValue);
        albumInfoIndex.setSubscribeStatNum(numberValue);
        albumInfoIndex.setCommentStatNum(numberValue);

        //  属性值信息.
        CompletableFuture<Void> attributeCompletableFuture = CompletableFuture.runAsync(() -> {
            Result<List<AlbumAttributeValue>> albumAttributeValueResult = albumInfoFeignClient.findAlbumAttributeValue(albumId);
            Assert.notNull(albumAttributeValueResult, "返回属性标签结果集为空");
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueResult.getData();
            //  判断
            if (!CollectionUtils.isEmpty(albumAttributeValueList)) {
                List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueList.stream().map(albumAttributeValue -> {
                    //  创建对象
                    AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                    //  赋值：
                    attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                    attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                    //  返回数据
                    return attributeValueIndex;
                }).collect(Collectors.toList());
                //  存储数据
                albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
            }
        }, threadPoolExecutor);

        //  做个多任务组合：
        CompletableFuture.allOf(
                albumInfoCompletableFuture,
                userInfoCompletableFuture,
                categoryCompletableFuture,
                attributeCompletableFuture
        ).join();
        //  保存数据： 能否并行操作?
        //  将albumInfoIndex保存到es中.  先有索引库;需要根据albumInfoIndex类的字段数据类型创建.
        albumIndexRepository.save(albumInfoIndex);

        //  初始化专辑提词数据.
        //  创建对象一个对象
        //  夜色钢琴曲--title.
        SuggestIndex suggestIndexTitle = new SuggestIndex();
        suggestIndexTitle.setId(UUID.randomUUID().toString());
        suggestIndexTitle.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndexTitle.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndexTitle.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndexTitle.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        suggestIndexRepository.save(suggestIndexTitle);

        //  保存专辑简介
        SuggestIndex suggestIndexIntro = new SuggestIndex();
        suggestIndexIntro.setId(UUID.randomUUID().toString());
        suggestIndexIntro.setTitle(albumInfoIndex.getAlbumIntro());
        suggestIndexIntro.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        suggestIndexIntro.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumIntro())}));
        suggestIndexIntro.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumIntro())}));
        suggestIndexRepository.save(suggestIndexIntro);

        //  保存作者：

        //  向布隆过滤器中添加专辑Id
        RBloomFilter<Object> bloomFilter = this.redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);
    }

    public static void main(String[] args) {
        System.out.println("夜色钢琴曲".split(""));
    }
}
